/**
 * @description - how to use
 ```
    async function asyncTaskWithCb(cb) {
        let err, user, savedTask, notification;

        [ err, user ] = await to(UserModel.findById(1));
        if(!user) return cb('No user found');

        [ err, savedTask ] = await to(TaskModel({userId: user.id, name: 'Demo Task'}));
        if(err) return cb('Error occurred while saving task');

        cb(null, savedTask);
    }

    async function asyncFunctionWithThrow() {
      const [err, user] = await to(UserModel.findById(1));
      if (!user) throw new Error('User not found');
    }
 ```
 */

/**
 * @param { Promise } promise
 * @param { Object= } errorExt - Additional Information you can pass to the err object
 * @return { Promise }
 */
export function to<T, U = Error>(
  promise: Promise<T>,
  errorExt?: Record<string, any>,
): Promise<[U, undefined] | [null, T]> {
  return promise
    .then<[null, T]>((data: T) => [null, data])
    .catch<[U, undefined]>((err: U) => {
      if (errorExt) {
        const parsedError = { ...err, ...errorExt }
        return [parsedError, undefined]
      }

      return [err, undefined]
    })
}
